import { useCallback, useReducer, useState } from "react";
const UNDO = "UNDO";
const REDO = "REDO";
const SET = "SET";
const RESET = "RESET";

type State<T> = {
  past: T[];
  present: T;
  feture: T[];
};
type Action<T> = {
  newpresent?: T;
  type: typeof UNDO | typeof REDO | typeof SET | typeof RESET;
};

const undoReducer = <T>(state: State<T>, action: Action<T>) => {
  const { past, present, feture } = state;
  const { newpresent } = action;
  switch (action.type) {
    case UNDO: {
      if (past.length == 0) {
        return state;
      }
      const previous = state.past[past.length - 1];
      const newPast = past.slice(0, past.length - 1);
      return {
        past: newPast,
        present: previous,
        feture: [present, ...feture],
      };
    }
    case REDO: {
      if (feture.length == 0) return state;

      const next = feture[0];
      const newFuture = feture.slice(1);
      return {
        past: [...past, present],
        present: next,
        feture: newFuture,
      };
    }
    case SET: {
      if (newpresent === present) {
        return state;
      }
      return {
        past: [...past, present],
        present: newpresent,
        feture: [],
      };
    }
    case RESET: {
      return {
        past: [],
        present: newpresent,
        feture: [],
      };
    }
  }
  return state;
};
export const useUndo = <T>(initalPresent: T) => {
  const [state, dispatch] = useReducer(undoReducer, {
    past: [],
    present: initalPresent,
    feture: [],
  } as State<T>);
  const canUndo = state.past.length !== 0;
  const canRedo = state.feture.length !== 0;
  const undo = useCallback(() => {
    dispatch({ type: UNDO });
  }, []);
  const redo = useCallback(() => {
    dispatch({ type: REDO });
  }, []);
  const set = useCallback((newpresent: T) => {
    dispatch({ type: SET, newpresent });
  }, []);
  const reset = useCallback((newpresent: T) => {
    dispatch({ type: RESET, newpresent });
  }, []);
  return [state, { set, reset, undo, redo, canUndo, canRedo }] as const;
};
